﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using XcoAppSpaces.Contracts.CcrWiring;
using XcoAppSpaces.Contracts.Service;
using XcoAppSpaces.Serialization.Binary;
using System.IO;
using Rhino.Mocks;
using System.Runtime.Serialization;

namespace test.XcoAppSpaces.Serialization.Binary
{

	[TestFixture]
	public class testSerialization
	{
		private MockRepository mocks;
		private XcoBinarySerializer serializer;

		[SetUp]
		public void SetUp()
		{
			mocks = new MockRepository();

			var ccrWirerMock = new CcrWirerMock(); //mocks.StrictMock<ICcrWirer>(); //Mocking doesnt work for ICcrWirer??
			var serviceRegistryMock = mocks.StrictMock<IXcoServiceRegistry>();
			
			Expect.Call(serviceRegistryMock.Resolve<ICcrWirer>()).Return(ccrWirerMock).Repeat.Any();
			mocks.ReplayAll();

			serializer = new XcoBinarySerializer();
			serializer.Initialize(serviceRegistryMock);

		}

		[TearDown]
		public void TearDown()
		{
			mocks.VerifyAll();
		}

		[Test]
		public void TestSerializeDeserialize_Simple()
		{
			TestSerializeDeserialize(null);
		}

		[Test]
		public void TestSerializeDeserialize_WithGenericType()
		{
			TestSerializeDeserialize(typeof(List<string>));
		}

		private void TestSerializeDeserialize(Type typeToSerialize)
		{
			var testObj = new TestType {someType = typeToSerialize};

			var serialized = serializer.Serialize(testObj);
			var deserialized = serializer.Deserialize(serialized) as TestType;

			Assert.IsNotNull(deserialized);
			Assert.AreEqual(testObj.value1, deserialized.value1);
			Assert.AreEqual(testObj.value2, deserialized.value2);
			Assert.AreEqual(testObj.someType, deserialized.someType);
		}

		[Test]
		public void CanBeSerialized()
		{
			string errorInfo;
			Assert.IsTrue(serializer.CanTypeBeSerialized(typeof(int), out errorInfo));
			Assert.IsTrue(serializer.CanTypeBeSerialized(typeof(string), out errorInfo));
			Assert.IsTrue(serializer.CanTypeBeSerialized(typeof(DateTime), out errorInfo));
			Assert.IsTrue(serializer.CanTypeBeSerialized(typeof(SerializableClass), out errorInfo));
			Assert.IsTrue(serializer.CanTypeBeSerialized(typeof(SerializableInterface), out errorInfo));
			Assert.IsFalse(serializer.CanTypeBeSerialized(typeof(NotSerializableClass), out errorInfo));
		}
		[Serializable]
		class SerializableClass {}
		class NotSerializableClass {}
		interface SerializableInterface {}

		private const string serializedTypeFilename = "Testtypes\\typeFromExternalAssembly.serialized";

		[Test, Explicit]
		public void SerializeTypeFromExternalAssemblyToFile()
		{
			//generates the file with the serialized external type that is used for the test below
			var obj = new TypeWithTypeField { SomeType = typeof(AssemblyWithTestType.TypeFromOtherAssembly) };
			var serialized = serializer.Serialize(obj);
			File.WriteAllBytes(serializedTypeFilename, serialized);
		}

		[Test]
		public void TypeFromExternalAssemblyCanBeDeserialized()
		{
			//This test checks if a Type can be deserialized although the Assembly has not yet been loaded (but is available in the application's path)
			
			System.Diagnostics.Debug.WriteLine("Test is starting now"); //Assembly "AssemblyWithTestType" should be loaded after this statement (see in debug console window)
			
			var serialized = File.ReadAllBytes(serializedTypeFilename);

			var deserialized = serializer.Deserialize(serialized);

			Assert.IsInstanceOf<TypeWithTypeField>(deserialized);
			Console.WriteLine(((TypeWithTypeField)deserialized).SomeType.ToString());
		}
	}
}
